package com.jinzhi.jzweb.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.gson.Gson;
import com.jinzhi.common.domain.DictDO;
import com.jinzhi.common.service.DictService;
import com.jinzhi.common.utils.Result;
import com.jinzhi.common.wxpay.service.WxPayCommonService;
import com.jinzhi.common.wxpay.utils.ConstAppId;
import com.jinzhi.jzapi.domain.UserDO;
import com.jinzhi.jzapi.utils.JWTUtil;
import com.jinzhi.jzweb.controller.api.ApiJazSysContractController;
import com.jinzhi.jzweb.dao.JazCoursesDao;
import com.jinzhi.jzweb.dao.JazUserCommentDao;
import com.jinzhi.jzweb.domain.*;
import com.jinzhi.jzweb.domain.vo.JazCoursesOrdeVo;
import com.jinzhi.jzweb.service.*;
import com.jinzhi.jzweb.domain.JazCoursesDO;
import com.jinzhi.jzweb.domain.JazShippingAddressDO;
import com.jinzhi.wxpay.config.WxPayConfigZF;
import com.jinzhi.wxpay.enums.OrderStatus;
import com.jinzhi.wxpay.enums.wxpay.WxNotifyType;
import com.jinzhi.wxpay.util.OrderNoUtils;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.jinzhi.jzweb.dao.JazCoursesOrderDao;
import com.jinzhi.common.base.CoreServiceImpl;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 
 * <pre>
 * 课程订单表
 * </pre>
 * <small> 2024-05-13 17:00:28 | Long</small>
 */
@Service
public class JazCoursesOrderServiceImpl extends CoreServiceImpl<JazCoursesOrderDao, JazCoursesOrderDO> implements JazCoursesOrderService {

    @Resource
    private WxPayConfigZF wxPayConfigZF;
    @Autowired
    private JazSysUserService jazSysUserService;

    @Autowired
    private JazGroupOrderService jazGroupOrderService;

    @Autowired
    private JazGroupProdService jazGroupProdService; //团购活动表

    @Autowired
    private JazGroupActivityUserService jazGroupActivityUserService; //团购活动拼团用户表

    @Autowired
    private JazGroupActivityService jazGroupActivityService; //团购活动拼团表

    @Autowired
    private JazOrderDetailService jazOrderDetailService;

    private final WxPayCommonService wxPayCommonService;

    private final JazShippingAddressService jazShippingAddressService;

    private final JazCoursesDao jazCoursesDao;

    private final JazUserCommentDao jazUserCommentDao;

    private final DictService dictService;

    public JazCoursesOrderServiceImpl(WxPayCommonService wxPayCommonService,JazShippingAddressService jazShippingAddressService,JazCoursesDao jazCoursesDao,JazUserCommentDao jazUserCommentDao,DictService dictService){
        this.wxPayCommonService = wxPayCommonService;
        this.jazShippingAddressService = jazShippingAddressService;
        this.jazCoursesDao=jazCoursesDao;
        this.jazUserCommentDao = jazUserCommentDao;
        this.dictService = dictService;
    }

    private  final ReentrantLock lock = new ReentrantLock();

    /**
     * 阿姨端-创建订单
     * @param jazCoursesOrderDTO 订单类
     * @return
     */
    @Override
    public JazCoursesOrderDO creatOrder(JazCoursesOrderDO jazCoursesOrderDTO) {
        //去重校验 课程不能重复购买
        JazCoursesOrderDO jazCoursesOrderDO2 = this.selectOne(new EntityWrapper<JazCoursesOrderDO>().eq("user_id", jazCoursesOrderDTO.getUserId())
                .eq("courses_id", jazCoursesOrderDTO.getCoursesId())
                .eq("status", OrderStatus.SUCCESS.getType()));
        Assert.isNull(jazCoursesOrderDO2,"请勿重复下单");

        //通过用户id和课程id查询是否存在待付款的订单 存在则直接返回
        JazCoursesOrderDO jazCoursesOrderDO = this.selectOne(new EntityWrapper<JazCoursesOrderDO>().eq("user_id", jazCoursesOrderDTO.getUserId())
                .eq("courses_id", jazCoursesOrderDTO.getCoursesId())
                .eq("status", OrderStatus.NOT_PAY.getType()));
        if(null != jazCoursesOrderDO){
            return jazCoursesOrderDO;
        }
        //新建订单
        jazCoursesOrderDTO.setOrderNo(OrderNoUtils.getOrderNo());
        jazCoursesOrderDTO.setStatus(OrderStatus.NOT_PAY.getType());
        jazCoursesOrderDTO.setAddressId(jazCoursesOrderDTO.getAddressId());
        //生产课程订单编号 课程订单编号 = 下单时间 + 00 + 订单计数器;
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        Integer noNum = creatCoursesNo();
        jazCoursesOrderDTO.setNoNum(noNum);
        jazCoursesOrderDTO.setCoursesNo(ApiJazSysContractController.generateOrderNumber(20));
        this.insert(jazCoursesOrderDTO);
        return jazCoursesOrderDTO;
    }

    /**
     * 阿姨端-课程支付接口
     * @param jazCoursesOrderDTO
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> jsapiPay(JazCoursesOrderDO jazCoursesOrderDTO) {
        String orderName = jazCoursesOrderDTO.getOrderName();
        String openid = jazCoursesOrderDTO.getOpenid();
        BigDecimal totalFee = jazCoursesOrderDTO.getTotalFee();
        //1.创建订单
        JazCoursesOrderDO jazCoursesOrderDO = creatOrder(jazCoursesOrderDTO);

        //2.调用系统微信小程序支付
        try {
            Map<String, Object> stringObjectMap = wxPayCommonService.jsapiNativePay(orderName, ConstAppId.AUNT_APP, openid, totalFee, jazCoursesOrderDO.getOrderNo(), WxNotifyType.NATIVE_NOTIFYS.getType());

            return stringObjectMap;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    /**
     * 阿姨端-课程退款接口
     * @param jazCoursesOrderDTO
     * @return
     */
    @Override
    @Transactional
    public Result<?>  jsapiRefund(JazCoursesOrderDO jazCoursesOrderDTO) {
        //1.查询需要退款的的订单
        JazCoursesOrderDO jazCoursesOrderDO = this.selectOne(new EntityWrapper<JazCoursesOrderDO>().eq("order_no",jazCoursesOrderDTO.getOrderNo()));
        //2.调用系统微信小程序退款
        try {

            return wxPayCommonService.jsapiRefund(jazCoursesOrderDO.getTransactionId(), OrderNoUtils.getOrderNo(), jazCoursesOrderDO.getTotalFee(), jazCoursesOrderDO.getTotalFee());

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 阿姨端取消订单 (同一个阿姨取消同一个订单 只会有一条取消记录)
     * @param orderId
     * @return
     */
    @Override
    public Result<?> cancelOrder(Long orderId) {
        //通过订单id查询订单消息
        JazCoursesOrderDO jazCoursesOrderDO1 = this.selectById(orderId);
        //查询同一个用户支付的同一个商品是否已经取消
        JazCoursesOrderDO jazCoursesOrderDO2 = this.selectOne(new EntityWrapper<JazCoursesOrderDO>().eq("courses_id", jazCoursesOrderDO1.getCoursesId()).eq("user_id", jazCoursesOrderDO1.getUserId()).eq("status", OrderStatus.CANCEL.getType()));
        if(jazCoursesOrderDO2!=null){
            return Result.ok();
        }else{
            JazCoursesOrderDO jazCoursesOrderDO = new JazCoursesOrderDO();
            jazCoursesOrderDO.setId(orderId);
            jazCoursesOrderDO.setStatus(OrderStatus.CANCEL.getType());
            boolean b = this.updateById(jazCoursesOrderDO);

            return b?Result.ok():Result.fail();
        }
    }


    /**
     * 支付成功，处理订单状态
     * @param bodyMap
     */
    @Override
    public void processOrder(Map<String, Object> bodyMap) {
        //解密报文
        String plainText = null;
        try {
            plainText = decryptFromResource(bodyMap);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText,HashMap.class);//将报文转换为json字符串
        String orderNo = (String) plainTextMap.get("out_trade_no");//订单号
        String transactionId = (String) plainTextMap.get("transaction_id");//微信支付订单号
        /**
         * 在对业务数据进行状态检查和处理前，要采用数据锁惊进行并发控制
         * 以免函数重入造成数据混乱
         * ：支付过程中可能出现两个人同时支付，返回数据同时出现，后面的更改订单状态也会同时更改这样就会出现数据混乱的问题
         * ：这里就要做一个高并发的水处理
         * */

        //获取锁，成功获取则立即返回true，获取失败返回false。这里的锁是如果获取失败就立即退出了，不会进行等待，不必等待锁的释放（会先跳出然后执行后面锁的释放）（与分布式事务锁不同(通常可以使用Redis或mq的分布式事务锁，这里的锁在分布式项目中锁不住)）
        if (lock.tryLock()){//加个锁，做一个并发处理
            try{
                //处理重复的通知（根据订单号查询订单状态（已支付，未支付）），如果支付过程中出现了问题(如网络问题，出现了支付中断)，那么微信支付会一直发送支付通知，这里需要处理一下
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。（）
                JazCoursesOrderDO jazCoursesOrderDO = this.selectOne(new EntityWrapper<JazCoursesOrderDO>().eq("order_no", orderNo));
                if (!OrderStatus.NOT_PAY.getType().equals(jazCoursesOrderDO.getStatus())){//如果不是未支付（NOT_PAY为未支付）
                    return;//支付状态如果已未支付，那个就直接return，只有订单是未支付才能更改支付状态
                }
                //更新数据库中订单状态
                JazCoursesOrderDO jazCoursesOrderDO1 = new JazCoursesOrderDO();
                jazCoursesOrderDO1.setStatus(OrderStatus.SUCCESS.getType());
                jazCoursesOrderDO1.setTransactionId(transactionId);

                this.update(jazCoursesOrderDO1,new EntityWrapper<JazCoursesOrderDO>().eq("order_no", orderNo));
                System.out.println("收支明细===课程支付====");
                //收支明细记录数据
                JazOrderDetailDO jazOrderDetailDO=new JazOrderDetailDO();
                jazOrderDetailDO.setOrderCode(jazCoursesOrderDO.getCoursesNo());
                jazOrderDetailDO.setMoney(jazCoursesOrderDO.getTotalFee());
                jazOrderDetailDO.setType(0);
                jazOrderDetailDO.setUserId(jazCoursesOrderDO.getUserId());
                jazOrderDetailDO.setTradeDesc("课程支付");
                JazCoursesDO jazCoursesDO = jazCoursesDao.selectById(jazCoursesOrderDO.getCoursesId());
                jazOrderDetailDO.setProdName(jazCoursesDO.getName());
                jazOrderDetailDO.setTradeTime(jazCoursesOrderDO.getCreaterDate());
                jazOrderDetailService.insert(jazOrderDetailDO);
            }finally {
                //主动释放锁（使用了锁之后必须要主动释放锁）
                lock.unlock();
            }


        }

    }

    /**
     * 阿姨端将课程订单改为已读
     * @param orderIds 订单id 多个以逗号隔开
     */
    @Override
    public void updateReadStatus(String orderIds) {
        Assert.notNull(orderIds,"参数：'orderIds'不能为空");
        //id字符串转集合
        List<String> orderIdList = new ArrayList<>(Arrays.asList(orderIds.split(",")));
        JazCoursesOrderDO jazCoursesOrderDO = new JazCoursesOrderDO();
        jazCoursesOrderDO.setIsRead(1);
        this.update(jazCoursesOrderDO,new EntityWrapper<JazCoursesOrderDO>().in("id",orderIdList));

    }

    /**
     * 查询课程订单未读的待付款数量
     * @return
     */
    @Override
    public int getOrderStatusNum() {
        Long userId = JWTUtil.getUser().getId();
        int i = this.selectCount(new EntityWrapper<JazCoursesOrderDO>().eq("is_read", 0).eq("user_id", userId).eq("status", OrderStatus.NOT_PAY.getType()));
        return i;

    }

    /**
     * 设置默认评价
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setDefaultComment() {
        String descriptionId = getComment();
        //查询未评价并且已经支付的订单
        System.out.println("==================================== 执行定时器，设置课程默认好评");
        List<JazCoursesOrderDO> jazCoursesOrderDOS = baseMapper.queryNoComment();
        if(jazCoursesOrderDOS!=null && !jazCoursesOrderDOS.isEmpty()){
            jazCoursesOrderDOS.forEach(jazCoursesOrderDO->{
                //修改为已读
                jazCoursesOrderDO.setHasComment(1);
                this.updateById(jazCoursesOrderDO);
                //新增评论
                JazUserCommentDO jazUserCommentDO = new JazUserCommentDO();
                jazUserCommentDO.setCommentOrderId(jazCoursesOrderDO.getId());
                jazUserCommentDO.setType(1);
                jazUserCommentDO.setCommentdObjectid(jazCoursesOrderDO.getCoursesId());
                jazUserCommentDO.setCommentUserid(jazCoursesOrderDO.getUserId());
                jazUserCommentDO.setContent("系统默认好评");
                jazUserCommentDO.setCommentDescriptionId(descriptionId);
                jazUserCommentDO.setGrade("5");
                jazUserCommentDao.insert(jazUserCommentDO);
            });
        }
    }


    /**
     * 参团回调   支付成功，处理订单状态
     * @param bodyMap
     */
    @Override
    public void cyGroupProcessOrder(Map<String, Object> bodyMap) {
        //解密报文
        String plainText = null;
        try {
            plainText = decryptFromResource(bodyMap);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText,HashMap.class);//将报文转换为json字符串
        String orderNo = (String) plainTextMap.get("out_trade_no");//订单号
        String transactionId = (String) plainTextMap.get("transaction_id");//微信支付订单号
        /**
         * 在对业务数据进行状态检查和处理前，要采用数据锁惊进行并发控制
         * 以免函数重入造成数据混乱
         * ：支付过程中可能出现两个人同时支付，返回数据同时出现，后面的更改订单状态也会同时更改这样就会出现数据混乱的问题
         * ：这里就要做一个高并发的水处理
         * */

        //获取锁，成功获取则立即返回true，获取失败返回false。这里的锁是如果获取失败就立即退出了，不会进行等待，不必等待锁的释放（会先跳出然后执行后面锁的释放）（与分布式事务锁不同(通常可以使用Redis或mq的分布式事务锁，这里的锁在分布式项目中锁不住)）
        if (lock.tryLock()){//加个锁，做一个并发处理
            try{
                //处理重复的通知（根据订单号查询订单状态（已支付，未支付）），如果支付过程中出现了问题(如网络问题，出现了支付中断)，那么微信支付会一直发送支付通知，这里需要处理一下
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。（）
                JazGroupOrderDO jazGroupOrderDO = jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("wx_order_no", orderNo));
                if (!OrderStatus.NOT_PAY.getType().equals(jazGroupOrderDO.getWxStatus())){//如果不是未支付（NOT_PAY为未支付）
                    return;//支付状态如果已未支付，那个就直接return，只有订单是未支付才能更改支付状态
                }
                if (jazGroupOrderDO.getOrderPayType() == 1){ //团购订单
                    //新增拼团关联的用户信息
                    JazGroupActivityUserDO jazGroupActivityUserDO= new JazGroupActivityUserDO();
                    jazGroupActivityUserDO.setGroupActivityId(jazGroupOrderDO.getGroupActivityId());
                    jazGroupActivityUserDO.setUserId(jazGroupOrderDO.getUserId());
//                    jazGroupActivityUserDO.setAddressId(jazGroupOrderDO.getAddressId());
                    Integer actityUserSortMax = getActityUserSortMax(jazGroupOrderDO.getGroupActivityId()); //获取拼团的序号
                    jazGroupActivityUserDO.setSort(actityUserSortMax + 1); //往后推一位
                    jazGroupActivityUserDO.setCreateTime(new Date());
                    jazGroupActivityUserService.insert(jazGroupActivityUserDO);

                    List<UserDO> userDOS = jazGroupActivityService.getUserByActivityId(jazGroupOrderDO.getGroupActivityId()); //新增完去查询该订单人数
                    JazGroupProdDO jazGroupProdDO = jazGroupProdService.selectById(jazGroupOrderDO.getGroupProdId()); //查询出拼团商品活动信息
                    System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++人快满了"+userDOS.size());
                    if (userDOS.size() == jazGroupProdDO.getPeopleNum()) { //如果拼团人数满了
                        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++人满了");
                        JazGroupActivityDO jazGroupActivity = jazGroupActivityService.selectById(jazGroupOrderDO.getGroupActivityId()); //查询拼团信息
                        jazGroupActivity.setStatus(1); //已完成拼团
                        jazGroupActivityService.updateById(jazGroupActivity);
                        //查询该拼团下面的用户
                        Wrapper<JazGroupActivityUserDO> groupActivityUserWapper = new EntityWrapper<>();
                        groupActivityUserWapper.eq("group_activity_id",jazGroupActivity.getId());
                        List<JazGroupActivityUserDO> jazGroupActivityUserDOS = jazGroupActivityUserService.selectList(groupActivityUserWapper);
                        for (int i =0;i<jazGroupActivityUserDOS.size();i++){
                            Wrapper<JazGroupOrderDO> groupOrderDOEntityWrapper = new EntityWrapper<>();
                            groupOrderDOEntityWrapper.eq("user_id",jazGroupActivityUserDOS.get(i).getUserId());
                            groupOrderDOEntityWrapper.eq("group_prod_id",jazGroupActivity.getGroupProdId());
                            groupOrderDOEntityWrapper.eq("group_specs_id",jazGroupActivity.getGroupSpecsId());
                            JazGroupOrderDO jazGroupOrderDOUpdate = jazGroupOrderService.selectOne(groupOrderDOEntityWrapper);
                            jazGroupOrderDOUpdate.setOrderStatus(1);//待使用
                            jazGroupOrderService.updateById(jazGroupOrderDOUpdate);
                        }
                    }

                }
                //更新数据库中订单状态
                JazGroupOrderDO jazGroupOrderDO1 = new JazGroupOrderDO();
                jazGroupOrderDO1.setWxStatus(OrderStatus.SUCCESS.getType());
                jazGroupOrderDO1.setWxTransactionId(transactionId);
                jazGroupOrderService.update(jazGroupOrderDO1,new EntityWrapper<JazGroupOrderDO>().eq("wx_order_no", orderNo));
                System.out.println("收支明细===参团回调   支付成功，处理订单状态====");
                //收支明细记录数据
                jazGroupOrderDO=jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("order_no", jazGroupOrderDO.getOrderNo()));
                JazOrderDetailDO jazOrderDetailDO=new JazOrderDetailDO();
                jazOrderDetailDO.setOrderCode(jazGroupOrderDO.getOrderNo());
                jazOrderDetailDO.setMoney(jazGroupOrderDO.getShareMoney());
                jazOrderDetailDO.setUserId(jazGroupOrderDO.getUserId());
                jazOrderDetailDO.setType(0);
                if (jazGroupOrderDO.getOrderPayType()!=null&&jazGroupOrderDO.getOrderPayType().equals(1)){
                    jazOrderDetailDO.setTradeDesc("团购支付");
                }else {
                    jazOrderDetailDO.setTradeDesc("订单支付");
                }
                JazGroupProdDO jazGroupProdDO = jazGroupProdService.selectById(jazGroupOrderDO.getGroupProdId());
                jazOrderDetailDO.setProdName(jazGroupProdDO.getName());
                jazOrderDetailDO.setTradeTime(jazGroupOrderDO.getCreateTime());
                jazOrderDetailService.insert(jazOrderDetailDO);
//                jazGroupOrderDO=jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("order_no", orderNo));
                System.out.println("用户id====+"+jazGroupOrderDO.getUserId());
            }finally {
                //主动释放锁（使用了锁之后必须要主动释放锁）
                lock.unlock();
            }

        }

    }



    /**
     * 获取拼团用户的最大排序号
     * @param groupActivityId
     * @return
     */
    private Integer getActityUserSortMax(Long groupActivityId){
        List<UserDO> userDOS = jazGroupActivityService.getUserByActivityId(groupActivityId);//查询参团人员
        UserDO userDO = userDOS.get(userDOS.size()-1); //获取排序后的最后一条数据
        Wrapper<JazGroupActivityUserDO> jazGroupActivityUserDOEntityWrapper = new EntityWrapper<>();
        jazGroupActivityUserDOEntityWrapper.eq("group_activity_id",groupActivityId);
        jazGroupActivityUserDOEntityWrapper.eq("user_id",userDO.getId());
        JazGroupActivityUserDO jazGroupActivityUserDO = jazGroupActivityUserService.selectOne(jazGroupActivityUserDOEntityWrapper);
        Integer sort = jazGroupActivityUserDO.getSort();
        return sort;
    }






    /**
     * 支付成功，处理订单状态
     * @param bodyMap
     */
    @Override
    public void groupProcessOrder(Map<String, Object> bodyMap) {
        //解密报文
        String plainText = null;
        try {
            plainText = decryptFromResource(bodyMap);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText,HashMap.class);//将报文转换为json字符串
        String orderNo = (String) plainTextMap.get("out_trade_no");//订单号
        String transactionId = (String) plainTextMap.get("transaction_id");//微信支付订单号
        /**
         * 在对业务数据进行状态检查和处理前，要采用数据锁惊进行并发控制
         * 以免函数重入造成数据混乱
         * ：支付过程中可能出现两个人同时支付，返回数据同时出现，后面的更改订单状态也会同时更改这样就会出现数据混乱的问题
         * ：这里就要做一个高并发的水处理
         * */

        //获取锁，成功获取则立即返回true，获取失败返回false。这里的锁是如果获取失败就立即退出了，不会进行等待，不必等待锁的释放（会先跳出然后执行后面锁的释放）（与分布式事务锁不同(通常可以使用Redis或mq的分布式事务锁，这里的锁在分布式项目中锁不住)）
        if (lock.tryLock()){//加个锁，做一个并发处理
            try{
                //处理重复的通知（根据订单号查询订单状态（已支付，未支付）），如果支付过程中出现了问题(如网络问题，出现了支付中断)，那么微信支付会一直发送支付通知，这里需要处理一下
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。（）
                JazGroupOrderDO jazGroupOrderDO = jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("wx_order_no", orderNo));
                if (!OrderStatus.NOT_PAY.getType().equals(jazGroupOrderDO.getWxStatus())){//如果不是未支付（NOT_PAY为未支付）
                    return;//支付状态如果已未支付，那个就直接return，只有订单是未支付才能更改支付状态
                }

                if (jazGroupOrderDO.getOrderPayType() == 1){ //团购订单
                    //新增拼团信息
                    JazGroupActivityDO jazGroupActivityDO =new JazGroupActivityDO();
                    jazGroupActivityDO.setStatus(0); //拼团中
                    jazGroupActivityDO.setSponsorUserId(jazGroupOrderDO.getUserId()); //发起人用户id
                    jazGroupActivityDO.setGroupProdId(jazGroupOrderDO.getGroupProdId()); //拼团活动商品id
                    jazGroupActivityDO.setCreateTime(new Date()); //拼团时间
                    jazGroupActivityDO.setGroupSpecsId(jazGroupOrderDO.getGroupSpecsId()); //规格id
                    jazGroupActivityService.insert(jazGroupActivityDO);
                    Long groupActivityId = jazGroupActivityDO.getId();

                    //新增拼团关联的用户信息
                    JazGroupActivityUserDO jazGroupActivityUserDO= new JazGroupActivityUserDO();
                    jazGroupActivityUserDO.setGroupActivityId(groupActivityId);
                    jazGroupActivityUserDO.setUserId(jazGroupOrderDO.getUserId());
//                    jazGroupActivityUserDO.setAddressId(jazGroupOrderDO.getAddressId());
                    jazGroupActivityUserDO.setSort(1);
                    jazGroupActivityUserDO.setCreateTime(new Date());
                    jazGroupActivityUserService.insert(jazGroupActivityUserDO);

                    jazGroupOrderDO.setGroupActivityId(groupActivityId);
                    jazGroupOrderService.updateById(jazGroupOrderDO);

                    JazGroupProdDO jazGroupProdDO = jazGroupProdService.selectById(jazGroupOrderDO.getGroupProdId());
                    jazGroupProdDO.setNum(jazGroupProdDO.getNum()+1); //销售数量+1
                    jazGroupProdService.updateById(jazGroupProdDO);
                    setCountdownAndExpire(jazGroupProdDO.getCountDown() * 60 * 60,jazGroupActivityDO.getId());//调用倒计时接口，结束后自动执行更改状态方法。
                }

                //更新数据库中订单状态
                JazGroupOrderDO jazGroupOrderDO1 = new JazGroupOrderDO();
                jazGroupOrderDO1.setWxStatus(OrderStatus.SUCCESS.getType());
                jazGroupOrderDO1.setWxTransactionId(transactionId);
                jazGroupOrderService.update(jazGroupOrderDO1,new EntityWrapper<JazGroupOrderDO>().eq("wx_order_no", orderNo));

                System.out.println("收支明细====支付成功，处理订单状态====");
                //收支明细记录数据
                jazGroupOrderDO=jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("order_no", jazGroupOrderDO.getOrderNo()));

                JazOrderDetailDO jazOrderDetailDO=new JazOrderDetailDO();
                jazOrderDetailDO.setOrderCode(jazGroupOrderDO.getOrderNo());
                jazOrderDetailDO.setMoney(jazGroupOrderDO.getShareMoney());
                jazOrderDetailDO.setUserId(jazGroupOrderDO.getUserId());
                jazOrderDetailDO.setType(0);
                if (jazGroupOrderDO.getOrderPayType()!=null&&jazGroupOrderDO.getOrderPayType().equals(1)){
                    jazOrderDetailDO.setTradeDesc("团购支付");
                }else {
                    jazOrderDetailDO.setTradeDesc("订单支付");
                }

                JazGroupProdDO jazGroupProdDO = jazGroupProdService.selectById(jazGroupOrderDO.getGroupProdId());
                jazOrderDetailDO.setProdName(jazGroupProdDO.getName());
                jazOrderDetailDO.setTradeTime(jazGroupOrderDO.getCreateTime());
                jazOrderDetailService.insert(jazOrderDetailDO);
//                jazGroupOrderDO=jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("order_no", orderNo));
                System.out.println("用户id====+"+jazGroupOrderDO.getUserId());
            }finally {
                //主动释放锁（使用了锁之后必须要主动释放锁）
                lock.unlock();
            }

        }

    }


    /**
     * 方法用于设置倒计时并自动结束订单  异步方法，以秒为单位
     * @param countdownSeconds  倒计时秒数
     * @param groupId  团购活动id
     */
    @Async
    public void setCountdownAndExpire(int countdownSeconds,Long groupId) {
        // 计算到期时间
        Date currentTime = new Date();
        long expireTimeMillis = currentTime.getTime() + (countdownSeconds * 1000); // 将秒转换为毫秒
        Date expireTime = new Date(expireTimeMillis);

        // 设置定时器，在到期时间时自动结束订单
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                expireOrder(groupId);
            }
        }, expireTime);
    }




    /**
     * 拼团倒计时结束或者人满调用该方法结束拼团。
     */
    private void expireOrder(Long groupId) {
        System.out.println("团购 " + groupId + " 已过期！");
        JazGroupActivityDO jazGroupActivityDO = jazGroupActivityService.selectById(groupId);
        if (jazGroupActivityDO.getStatus()!=1){
            jazGroupActivityDO.setStatus(1); //设置状态为已完成。
            jazGroupActivityService.updateById(jazGroupActivityDO);
        }
        //查询该拼团下面的用户
        Wrapper<JazGroupActivityUserDO> groupActivityUserWapper = new EntityWrapper<>();
        groupActivityUserWapper.eq("group_activity_id",jazGroupActivityDO.getId());
        List<JazGroupActivityUserDO> jazGroupActivityUserDOS = jazGroupActivityUserService.selectList(groupActivityUserWapper);
        for (int i =0;i<jazGroupActivityUserDOS.size();i++){
            Wrapper<JazGroupOrderDO> groupOrderDOEntityWrapper = new EntityWrapper<>();
            groupOrderDOEntityWrapper.eq("user_id",jazGroupActivityUserDOS.get(i).getUserId());
            groupOrderDOEntityWrapper.eq("group_prod_id",jazGroupActivityDO.getGroupProdId());
            groupOrderDOEntityWrapper.eq("group_specs_id",jazGroupActivityDO.getGroupSpecsId());
            JazGroupOrderDO jazGroupOrderDO = jazGroupOrderService.selectOne(groupOrderDOEntityWrapper);
            if (jazGroupOrderDO.getOrderStatus() == 0) {
                jazGroupOrderDO.setOrderStatus(1);//待使用
                jazGroupOrderService.updateById(jazGroupOrderDO);
            }
        }
    }



    /**
     * 改为已退款
     * @param bodyMap
     */
    @Override
    public void upRefundStatus(Map<String, Object> bodyMap) {

        //解密报文
        String plainText = null;
        try {
            plainText = decryptFromResource(bodyMap);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText,HashMap.class);//将报文转换为json字符串
        String orderNo = (String) plainTextMap.get("out_trade_no");//订单号
        /**
         * 在对业务数据进行状态检查和处理前，要采用数据锁惊进行并发控制
         * 以免函数重入造成数据混乱
         * ：支付过程中可能出现两个人同时支付，返回数据同时出现，后面的更改订单状态也会同时更改这样就会出现数据混乱的问题
         * ：这里就要做一个高并发的水处理
         * */

        //获取锁，成功获取则立即返回true，获取失败返回false。这里的锁是如果获取失败就立即退出了，不会进行等待，不必等待锁的释放（会先跳出然后执行后面锁的释放）（与分布式事务锁不同(通常可以使用Redis或mq的分布式事务锁，这里的锁在分布式项目中锁不住)）
        if (lock.tryLock()){//加个锁，做一个并发处理
            try{
                //处理重复的通知（根据订单号查询订单状态（已支付，未支付）），如果支付过程中出现了问题(如网络问题，出现了支付中断)，那么微信支付会一直发送支付通知，这里需要处理一下
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。（）
                JazCoursesOrderDO jazCoursesOrderDO = new JazCoursesOrderDO();
                jazCoursesOrderDO.setStatus(OrderStatus.CANCEL.getType());
                this.update(jazCoursesOrderDO,new EntityWrapper<JazCoursesOrderDO>().eq("order_no",orderNo));
            }finally {
                //主动释放锁（使用了锁之后必须要主动释放锁）
                lock.unlock();
            }


        }
    }





    /**
     * 改为已退款
     * @param bodyMap
     */
    @Override
    public void upOrderRefundStatus(Map<String, Object> bodyMap) {

        //解密报文
        String plainText = null;
        try {
            plainText = decryptFromResource(bodyMap);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText,HashMap.class);//将报文转换为json字符串
        String orderNo = (String) plainTextMap.get("out_refund_no");//订单号
        /**
         * 在对业务数据进行状态检查和处理前，要采用数据锁惊进行并发控制
         * 以免函数重入造成数据混乱
         * ：支付过程中可能出现两个人同时支付，返回数据同时出现，后面的更改订单状态也会同时更改这样就会出现数据混乱的问题
         * ：这里就要做一个高并发的水处理
         * */

        //获取锁，成功获取则立即返回true，获取失败返回false。这里的锁是如果获取失败就立即退出了，不会进行等待，不必等待锁的释放（会先跳出然后执行后面锁的释放）（与分布式事务锁不同(通常可以使用Redis或mq的分布式事务锁，这里的锁在分布式项目中锁不住)）
        if (lock.tryLock()){//加个锁，做一个并发处理
            try{
                //处理重复的通知（根据订单号查询订单状态（已支付，未支付）），如果支付过程中出现了问题(如网络问题，出现了支付中断)，那么微信支付会一直发送支付通知，这里需要处理一下
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。（）
                JazGroupOrderDO jazGroupOrderDO = new JazGroupOrderDO();
                jazGroupOrderDO.setWxStatus(OrderStatus.CANCEL.getType());
                jazGroupOrderDO.setOrderStatus(3); //修改订单状态为已退款
                jazGroupOrderDO.setRefundTime(new Date());
                jazGroupOrderService.update(jazGroupOrderDO,new EntityWrapper<JazGroupOrderDO>().eq("order_no",orderNo));
                JazGroupOrderDO jazGroupOrderDO1 = jazGroupOrderService.selectOne(new EntityWrapper<JazGroupOrderDO>().eq("order_no", orderNo));

                System.out.println("收支明细====退款====");
                //收支明细记录数据
                JazOrderDetailDO jazOrderDetailDO=new JazOrderDetailDO();
                jazOrderDetailDO.setOrderCode(jazGroupOrderDO1.getOrderNo());
                jazOrderDetailDO.setMoney(jazGroupOrderDO1.getShareMoney());
                jazOrderDetailDO.setUserId(jazGroupOrderDO1.getUserId());
                jazOrderDetailDO.setType(1);
                jazOrderDetailDO.setTradeDesc("退款");
                JazGroupProdDO jazGroupProdDO = jazGroupProdService.selectById(jazGroupOrderDO1.getGroupProdId());
                if (jazGroupProdDO!=null){
                    jazOrderDetailDO.setProdName(jazGroupProdDO.getName());
                    jazOrderDetailDO.setTradeTime(jazGroupOrderDO.getRefundTime());
                }
                jazOrderDetailService.insert(jazOrderDetailDO);
            }finally {
                //主动释放锁（使用了锁之后必须要主动释放锁）
                lock.unlock();
            }
        }
    }





    /**
     * 阿姨端-查询订单列表
     * @param jazCoursesOrderDTO
     * @return
     */
    @Override
    public Result<?> selOrderList(JazCoursesOrderDO jazCoursesOrderDTO) {
        EntityWrapper<JazCoursesOrderDO> wrapper = new EntityWrapper<>();
        if(null!=jazCoursesOrderDTO.getUserId()){
            wrapper.eq("user_id",jazCoursesOrderDTO.getUserId());
        }
        if(null!=jazCoursesOrderDTO.getStatus()){
            wrapper.eq("status",jazCoursesOrderDTO.getStatus());
        }
        Page<JazCoursesOrderDO> pageList = this.selectPage(new Page<JazCoursesOrderDO>(jazCoursesOrderDTO.getCurrent(), jazCoursesOrderDTO.getSize()), wrapper);
        pageList.getRecords().forEach(record->{
            //查询课程信息
            JazCoursesDO jazCoursesDO = jazCoursesDao.selectById(record.getCoursesId());
            record.setJazCoursesDO(jazCoursesDO);
            //查询用户是否评价
//            List<JazUserCommentDO> jazUserCommentDOS = jazUserCommentDao.selectList(new EntityWrapper<JazUserCommentDO>().eq("comment_userid", record.getUserId()).eq("commentd_objectid", record.getCoursesId()));
//            if(null!=jazUserCommentDOS && !jazUserCommentDOS.isEmpty()){
//                record.setHasComment(true);
//            }
        });

        return Result.ok(pageList);
    }

    /**
     * 阿姨端-订单详情
     * @param orderId
     * @return
     */
    @Override
    public Result<?> orderDetail(Long orderId) {
        //查询订单详情信息
        JazCoursesOrderDO jazCoursesOrderDO = this.selectById(orderId);
        //查询订单地址信息
        JazShippingAddressDO jazShippingAddressDO = jazShippingAddressService.selectById(jazCoursesOrderDO.getAddressId());
        jazCoursesOrderDO.setJazShippingAddressDO(jazShippingAddressDO);
        return Result.ok(jazCoursesOrderDO);
    }

    @Override
    public Result<Page<JazCoursesOrderDO>> selCourseOrderList(String name, String mobile, int current, int size, String createTime, String endTime, String status) {
        Page<JazCoursesOrderDO> page = new Page<>(current, size);
        Wrapper<JazCoursesOrderDO> wrapper=new EntityWrapper<>();
        boolean hasUserFilter = false;
        if (StringUtils.isNotBlank(mobile)) {
            List<UserDO> user = jazSysUserService.selectList(new EntityWrapper<UserDO>().like("mobile","%"+ mobile+"%"));
            if (!user.isEmpty()) {
                List<Long> userIds = user.stream().map(UserDO::getId).collect(Collectors.toList());
                wrapper.in("user_id", userIds);
            }else {
                // 如果没查到用户 返回空结果
                return Result.ok(new Page<>());
            }
        }
        if (StringUtils.isNotBlank(name)){
            List<UserDO> users = jazSysUserService.selectList(new EntityWrapper<UserDO>().like("username","%"+ name+"%"));
            if (!users.isEmpty()) {
                List<Long> userIds = users.stream().map(UserDO::getId).collect(Collectors.toList());
                wrapper.in("user_id", userIds);
            } else {
                // 如果没查到用户 返回空结果
                return Result.ok(new Page<>());
            }
        }
        if(StringUtils.isNotBlank(createTime) &&  StringUtils.isNotBlank(endTime)){
            wrapper.between("creater_date",createTime,endTime);
        }
        if (StringUtils.isNotBlank(status)){
            wrapper.eq("status", status);
        }
        wrapper.orderBy("creater_date",false);

        Page<JazCoursesOrderDO> jazGroupActivityDOPage = this.selectPage(page, wrapper);
        List<JazCoursesOrderDO> doList=new ArrayList<>();
        for (JazCoursesOrderDO jazCoursesOrderDO:jazGroupActivityDOPage.getRecords()){
            JazCoursesOrderDO d=new JazCoursesOrderDO();
            BeanUtils.copyProperties(jazCoursesOrderDO,d);
            d.setShareMoney(jazCoursesOrderDO.getTotalFee());
            JazCoursesDO jazCoursesDO = jazCoursesDao.selectById(d.getCoursesId());
            d.setCoursesName(jazCoursesDO.getName());
            d.setAccountMoney(jazCoursesDO.getPrice());
            UserDO user = jazSysUserService.selectById(jazCoursesOrderDO.getUserId());
            d.setUserName(null==user?"-":user.getUsername());
            d.setPhone(null==user?"-":user.getMobile());
            doList.add(d);
        }
        jazGroupActivityDOPage.setRecords(doList);
        return Result.ok(jazGroupActivityDOPage);
    }

    @Override
    public JazCoursesOrdeVo getInfo(Long id) {
        JazCoursesOrderDO jazCoursesOrderDO = this.selectById(id);
        JazCoursesOrdeVo vo=new JazCoursesOrdeVo();
        BeanUtils.copyProperties(jazCoursesOrderDO,vo);
        UserDO user = jazSysUserService.selectById(jazCoursesOrderDO.getUserId());
        vo.setAccountMoney(jazCoursesOrderDO.getTotalFee());
        if (jazCoursesOrderDO.getStatus().equals("支付成功")){
            vo.setShareMoney(jazCoursesOrderDO.getTotalFee());
        }else {
            vo.setShareMoney(BigDecimal.ZERO);
        }
        vo.setCoursesName(jazCoursesDao.selectById(vo.getCoursesId()).getName());
        vo.setUserName(null==user?"-":user.getUsername());
        vo.setPhone(null==user?"-":user.getMobile());
        //重新赋值
//        vo.setOrderNo(jazCoursesOrderDO.getCoursesNo());
        return vo;
    }

    /**
     * 对称解密
     *
     * @return*/
    private String decryptFromResource(Map<String, Object> bodyMap) throws GeneralSecurityException {
        log.info("解密");
        //通知数据
        Map<String,String> resourceMap = (Map) bodyMap.get("resource");
        //获取数据秘文
        String ciphertext = resourceMap.get("ciphertext");
        //获取随机串
        String nonce = resourceMap.get("nonce");
        //获取附加数据
        String associatedData = resourceMap.get("associated_data");


        AesUtil aesUtil = new AesUtil(wxPayConfigZF.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),ciphertext);
        log.info("明文=====》 {}",plainText);
        /**
         *
         * 包括:mchid(商户号),appid(微信id),transaction_id(微信生成的唯一订单号)
         * */
        log.info("秘文=====》 {}",ciphertext);
        return plainText;
    }

    /**
     * 生成订单计数器
     * @return
     */
    public Integer creatCoursesNo(){
        //获取目前最大的 noNum,再+1
        int noNum = 1;
        List<JazCoursesOrderDO> noNumList = this.selectList(new EntityWrapper<JazCoursesOrderDO>().orderBy("no_num", false));
        if(noNumList!=null && !noNumList.isEmpty()){
            noNum = noNumList.get(0).getNoNum() +1;
        }
        return  noNum;
    }


    public String getComment(){
        String comment = null;
        Map map = new HashMap();
        map.put("Type","system_comment");
        List<DictDO> dictDOS = dictService.selectListBy(map);
        if(dictDOS!=null && !dictDOS.isEmpty()){
            comment = dictDOS.get(0).getValue();
        }
        return comment;
    }



}
